<template>
    <div
        class="el-tree"
        :class="{
      'el-tree--highlight-current': highlightCurrent,
      'is-dragging': !!dragState.draggingNode,
      'is-drop-not-allow': !dragState.allowDrop,
      'is-drop-inner': dragState.dropType === 'inner'
    }"
        role="tree"
    >
        <!--
            这里将:render-content="renderContent"重写为:render-content="renderContent||itemRender"
            这是因为不能直接重写renderContent方法，通过这种方式避免报错
        -->
        <el-tree-node
            v-for="child in root.childNodes"
            :node="child"
            :props="props"
            :render-after-expand="renderAfterExpand"
            :show-checkbox="showCheckbox"
            :key="getNodeKey(child)"
            :render-content="renderContent||itemRender"
            @node-expand="handleNodeExpand"
        ></el-tree-node>
        <div class="el-tree__empty-block" v-if="isEmpty">
            <span class="el-tree__empty-text">{{ emptyText }}</span>
        </div>
        <div
            v-show="dragState.showDropIndicator"
            class="el-tree__drop-indicator"
            ref="dropIndicator"
        ></div>
    </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from "vue-property-decorator";
import { Tree } from "element-ui";
import { construct } from "@aximario/json-tree";
@Component({
    // 继承element-tree
    extends: Tree,
    name: "ZbTree"
})
export default class ZbTree extends Vue {
    // 非树形结构数据
    @Prop() readonly anyData!: Array<any>;
    // 全部展开或者全部折叠
    // 变量后加!避免报错
    @Prop(Boolean) readonly isExpandAll!: boolean;
    // 遍历单条数据
    @Prop() readonly formatterLabel!: Function;
    // 监听
    @Watch("isExpandAll")
    // 当isExpandAll变化时
    updateIsExpandAll(val: boolean) {
        this.treeFolding(val);
    }
    // 监听
    @Watch("anyData")
    updateAnyData() {
        this.setAnyData();
    }

    // 设置扁平数据
    setAnyData() {
        const me = this as any,
            data = me.anyData,
            props = me.props;
        if (!me.data && data) {
            const treeData = construct(data, {
                id: props.id,
                pid: props.layer,
                children: props.children
            });
            me.store.setData(treeData);
        }
    }
    // 初始化
    created() {
        const me = this as any;
        me.setAnyData();
        // 检查配置是否完整
        if (!me.nodeKey) {
            throw new Error("node-key必须配置，否则全部展开/折叠功能无法生效");
        }
        if (me.indent != "0") {
            throw new Error('必须配置:indent="0"，否则层级指示线会有显示问题');
        }
    }

    // 单项初始化时生成dom
    itemRender(h:any, { node, data }:any) {
        const isLeaf = !!data.children,
            formatterLabel = this.formatterLabel;
        // 有子节点和没有子节点显示的图标不一样
        let className = "el-icon-document",
            label = node.label;
        // 处理显示值
        // 最好不要在formatterLabel里面操作data,否则会有额外的性能消耗
        if (formatterLabel) {
            label = formatterLabel(data);
        }
        if (isLeaf) {
            // 展开与折叠图标
            className = node.expanded
                ? "el-icon-folder-opened"
                : "el-icon-folder";
        }
        return h(
            "span",
            {
                class: "el-tree-node-label " + className
            },
            label
        );
    }
    // 树形菜单展开或折叠，树形控件必须设置置node-key才能生效
    treeFolding(isExpand: boolean): void {
        // (this as any).store避免报语法错误
        const nodes = (this as any).store._getAllNodes(),
            length = nodes.length;
        let i = 0;
        for (; i < length; i++) {
            nodes[i].expanded = isExpand;
        }
    }
}
</script>

<style scoped lang="scss">
//树形层级指示线颜色
$el-tree-line-color: #cccccc !default;
//折叠展开按钮颜色
$el-tree-ico-color: #c0c4cc !default;
.el-tree /deep/ {
    .el-tree-node__children {
        padding-left: 16px;
    }
    //层级指示线部分
    .el-tree-node {
        position: relative;
        padding-left: 16px;
        //勾选框样式
        .el-checkbox {
            display: inherit;
            margin-right: 5px;
        }
        .el-tree-node-label {
            //文字和自定义图标需要一定的间隔
            &:before {
                color: #409eff;
                margin-right: 3px;
            }
        }
        //如果节点没有子节点，延长层级指示线
        .el-tree-node__expand-icon.is-leaf {
            position: relative;
            width: 15px;
            &:before {
                content: "";
                position: absolute;
                left: 6px;
                right: auto;
                border-width: 1px 0 0 0;
                border-top: 1px dashed $el-tree-line-color;
                width: 20px;
                height: 1px;
                top: 5px;
            }
        }

        &:before,
        &:after {
            content: "";
            left: -4px;
            position: absolute;
            right: auto;
            border-width: 1px;
        }
        &:before {
            border-left: 1px dashed $el-tree-line-color;
            bottom: 0px;
            height: 100%;
            top: -26px;
            width: 1px;
        }
        &:after {
            border-top: 1px dashed $el-tree-line-color;
            // 不能设值高，会遮挡折叠按钮，导致折叠按钮点击不灵敏
            // height: 20px;
            top: 12px;
            width: 24px;
        }
        &:last-child:before {
            height: 38px;
        }
    }
    //第一级无须层级指示线与内边距
    & > .el-tree-node {
        padding-left: 0 !important;
        &:before {
            border-left: none;
        }
        &:after {
            border-top: none;
        }
    }
    //展开折叠图标
    .el-tree-node__expand-icon {
        &.el-icon-caret-right:before {
            color: $el-tree-ico-color;
            //给一个默认边框
            border: 1px solid $el-tree-ico-color;
            //展开图标加号
            content: "\e6d9";
        }
        &.expanded {
            //默认折叠效果是箭头符号旋转实现，这里换成减号需禁用
            transform: none;
            &.el-icon-caret-right:before {
                //减号
                content: "\e6d8";
            }
        }
    }
}
</style>
